#pragma once
#include <Rz/IObject.h>
#include <Rz/String.h>

#include <functional>

RZ_CLASS_FWD_DECL3(Rz, Graphics, Render, ITexture2D);
RZ_CLASS_FWD_DECL3(Rz, Graphics, Render, IEffect);
RZ_CLASS_FWD_DECL3(Rz, Graphics, Math, Vector2);
RZ_CLASS_FWD_DECL3(Rz, Graphics, Math, Vector3);
RZ_CLASS_FWD_DECL3(Rz, Graphics, Math, Vector4);
RZ_CLASS_FWD_DECL3(Rz, Graphics, Math, Matrix3);
RZ_CLASS_FWD_DECL3(Rz, Graphics, Math, Matrix4);

namespace Rz { namespace Graphics { namespace Render {

class IEffectProperty :
	virtual public IObject
{
	public:
		RZ_RTTI_INTERFACE(Rz::Graphics::Render, IEffectProperty);
		RZ_RTTI_IMPLEMENTS(IObject);
		RZ_RTTI_END;

		virtual void Apply();

		virtual void Set(bool value);
		virtual void Set(s32 value);
		virtual void Set(f32 value);
		virtual void Set(const Math::Vector2& value);
		virtual void Set(const Math::Vector3& value);
		virtual void Set(const Math::Vector4& value);
		virtual void Set(const Math::Matrix3& value);
		virtual void Set(const Math::Matrix4& value);
		virtual void Set(const ITexture2D* value);

		virtual void operator = (bool value);
		virtual void operator = (s32 value);
		virtual void operator = (f32 value);
		virtual void operator = (const Math::Vector2& value);
		virtual void operator = (const Math::Vector3& value);
		virtual void operator = (const Math::Vector4& value);
		virtual void operator = (const Math::Matrix3& value);
		virtual void operator = (const Math::Matrix4& value);
		virtual void operator = (const ITexture2D* value);

		virtual const IEffect* GetEffect() const;
		virtual IEffect* GetEffect();
		
		virtual const String& GetPropertyName() const;
		virtual String& GetPropertyName();
		virtual void SetPropertyName(const String& propertyName);

	protected:
		// needs to be overriden
		virtual void SetBool(bool value) = 0;
		virtual void SetInt32(s32 value) = 0;
		virtual void SetFloat(f32 value) = 0;
		virtual void SetVector2(const Math::Vector2& value) = 0;
		virtual void SetVector3(const Math::Vector3& value) = 0;
		virtual void SetVector4(const Math::Vector4& value) = 0;
		virtual void SetMatrix3(const Math::Matrix3& value) = 0;
		virtual void SetMatrix4(const Math::Matrix4& value) = 0;
		virtual void SetTexture2D(const ITexture2D* value) = 0;

		virtual void SetEffect(IEffect* effect);

	private:
		// TODO: Ptr?
		IEffect* _effect;
		String _propertyName;
		std::function<void()> _setCallback;
};

} } }
